#include "ModuleManager.h"
#ifdef WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

ModuleManager::ModuleManager()
{

}

ModuleManager::~ModuleManager()
{

}

void ModuleManager::UnloadAllModules()
{
	boost::recursive_mutex::scoped_lock locker(m_lock);
	for (size_t n = 0; n < m_mudules.size(); ++n)
	{
		if (m_mudules[n].pModuleHandle)
		{
#ifdef WIN32
			fn_UnloadModule pUnloandModule = (fn_UnloadModule)GetProcAddress((HMODULE)m_mudules[n].pModuleInstance, "UnloadModule");
#else
			fn_UnloadModule pUnloandModule = (fn_UnloadModule)dlsym(m_mudules[n].pModuleInstance, "UnloadModule");			
#endif
			
			if (pUnloandModule)
			{
				pUnloandModule(m_mudules[n].pModuleHandle);
			}
		}

		if (m_mudules[n].pModuleInstance)
		{
#ifndef WIN32
			dlclose(m_mudules[n].pModuleInstance);
#else
			CloseHandle((HMODULE)m_mudules[n].pModuleInstance);
#endif
		}
	}

	m_mudules.clear();
}

bool ModuleManager::LoadModule(const char * pszModuleName, const char * pszModulePath, IServerObject * pServerObj)
{
	if (pServerObj == NULL || pszModuleName == NULL || pszModulePath == NULL)
	{
		return false;
	}

	boost::recursive_mutex::scoped_lock locker(m_lock);

	ModuleInfo info;
	memset(&info, 0x00, sizeof(info));
#ifdef WIN32
	info.pModuleInstance = (void*)LoadLibrary(pszModulePath);
#else
	info.pModuleInstance = dlopen(pszModulePath, RTLD_LAZY);
#endif
	
	if (info.pModuleInstance != NULL)
	{
#ifdef WIN32
		fn_LoadModule pCreator = (fn_LoadModule)GetProcAddress((HMODULE)info.pModuleInstance, "LoadModule");		
#else
		fn_LoadModule pCreator = (fn_LoadModule)dlsym(info.pModuleInstance, "LoadModule");
#endif
		
		if (pCreator)
		{
			info.pModuleHandle = pCreator(pszModuleName, pServerObj);
		}
	}

	bool bRtn = false;
	if (info.pModuleHandle != NULL)
	{
		m_mudules.push_back(info);
		strcpy(m_mudules.back().szModuleName, pszModuleName);
	}
	else
	{
		if (info.pModuleInstance)
		{
#ifdef WIN32
			CloseHandle((HMODULE)info.pModuleInstance);
#else	
			dlclose(info.pModuleInstance);
#endif
			
		}
	}

	return bRtn;
}

void ModuleManager::UnloadModule(const char * pszModuleName)
{
	if (pszModuleName == NULL)
	{
		return;
	}

	boost::recursive_mutex::scoped_lock locker(m_lock);

	int len = strlen(pszModuleName);
	for (size_t n = 0; n < m_mudules.size(); ++n)
	{
		if (strncmp(pszModuleName, m_mudules[n].szModuleName, len) == 0)
		{
			ModuleInfo info = m_mudules[n];
			m_mudules.erase(m_mudules.begin() + n);

			if (info.pModuleHandle)
			{
#ifdef WIN32
				fn_UnloadModule pUnloandModule = (fn_UnloadModule)GetProcAddress((HMODULE)info.pModuleInstance, "UnloadModule");
#else
				fn_UnloadModule pUnloandModule = (fn_UnloadModule)dlsym(info.pModuleInstance, "UnloadModule");
#endif
				
				if (pUnloandModule)
				{
					pUnloandModule(info.pModuleHandle);
				}
			}

			if (info.pModuleInstance)
			{
#ifdef WIN32
				CloseHandle((HMODULE)info.pModuleInstance);
#else	
				dlclose(info.pModuleInstance);
#endif
			}

			break;
		}
	}
}
